use std::sync::Arc;

use anyhow::{anyhow, Result};
use sea_orm::{ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, ModelTrait, QueryFilter};
use sea_orm::sea_query::any;

use crate::dto::point_dto::{PointDto, PointQuery};
use crate::entity::cfg_varsystem;
use crate::entity::cfg_varsystem::Model;
use crate::entity::prelude::CfgVarsystem;
use crate::util::str_util::to_table_name;

pub trait DbContextHolder {
    fn get_db_contexts(&self) -> &Vec<DatabaseConnection>;
    fn get_db_context(&self, machine_index: u32) -> &DatabaseConnection {
        let mut index = machine_index as usize;
        index = index - 1;
        self.get_db_contexts().get(index).expect(format!("没有找到第{}机组数据库连接", machine_index).as_str())
    }
}


pub struct PointRepo {
    db_contexts: Arc<Vec<DatabaseConnection>>,
}


impl DbContextHolder for PointRepo {
    fn get_db_contexts(&self) -> &Vec<DatabaseConnection> {
        &self.db_contexts
    }
}

impl PointRepo {
    pub fn new(dbs: Arc<Vec<DatabaseConnection>>) -> Self {
        Self { db_contexts: dbs }
    }

    pub async fn get_points_async(&self, machine_index: u32, para: PointQuery) -> Result<Vec<PointDto>> {
        let db_context = self.get_db_context(machine_index);
        let mut query = cfg_varsystem::Entity::find();
        // 叠加查询条件
        if let Some(name) = para.name {
            query = query.filter(cfg_varsystem::Column::Name.contains(name))
        }
        if let Some(description) = para.description {
            query = query.filter(cfg_varsystem::Column::Description.contains(description))
        }
        let ret = query.all(db_context).await;

        let models = match ret {
            Ok(models) => models,
            Err(err) => return Err(anyhow!("数据库错误: {}", err)),
        };
        // 校验 models 里面的item.name 是否为none ,如果是none 则返回错误
        if let Some(item) = models.iter().find(|item| item.name.is_none()) {
            return Err(anyhow!("点 id 为 {} 的点名为空", item.id));
        }
        let dtos = models.into_iter().map(|model| PointDto::from(model)).collect();
        Ok(dtos)
    }

    pub async fn get_points_by_ids_async(&self, machine_index: u32, ids: Vec<i32>) -> Result<Vec<PointDto>, String> {
        let db_context = self.get_db_context(machine_index);
        let mut query = CfgVarsystem::find();
        // 叠加查询条件
        query = query.filter(cfg_varsystem::Column::Id.is_in(ids));
        let ret = query.all(db_context).await;

        let models = match ret {
            Ok(models) => models,
            Err(err) => return Err(format!("数据库错误: {}", err)),
        };
        let dtos = models.into_iter().map(|model| PointDto::from(model)).collect();
        Ok(dtos)
    }

    pub async fn get_points_by_names_ignore_case(&self, machine_index: u32, names: Vec<String>) -> Result<Vec<PointDto>> {
        let new_names: Vec<String> = names.into_iter().map(to_table_name).collect();
        let db_context = self.get_db_context(machine_index);
        let mut query = CfgVarsystem::find();
        // 叠加查询条件
        query = query.filter(cfg_varsystem::Column::Name.is_in(new_names));
        let ret = query.all(db_context).await;
        let models = match ret {
            Ok(models) => models,
            Err(err) => return Err(anyhow!("数据库错误: {}", err)),
        };
        Ok(models.into_iter().map(PointDto::from).collect())
    }
    pub async fn update_point_async(&self, machine_index: u32, id: i32, val: PointDto) -> Result<Model> {
        let db_context = self.get_db_context(machine_index);
        let model = CfgVarsystem::find_by_id(id).one(db_context).await?;
        // Into ActiveModel
        let mut update_entity: cfg_varsystem::ActiveModel = model.unwrap().into();
        let active_model = val.to_model_update(update_entity);
        let ret = active_model.update(db_context).await?;
        Ok(ret)
    }
    pub(crate) async fn delete_point_by_id_async(&self, machine_index: u32, id: i32) -> Result<()> {
        let db_context = self.get_db_context(machine_index);
        let model = CfgVarsystem::find_by_id(id).one(db_context).await?.ok_or_else(|| anyhow!("没有找到id为{}的点", id))?;
        model.delete(db_context).await?;
        Ok(())
    }
}


